package home.my.base.dao;

import home.my.base.annotation.InitCollection;
import home.my.base.model.BaseObj;
import home.my.base.sql.AbsCondition;
import home.my.base.sql.ConditionQuery;
import home.my.base.util.DataBaseUtil;
import home.my.base.util.TypeUtil;
import home.my.base.util.downloader.DownLoader;
import home.my.recordmanage.util.GlobalParameters;

import java.io.Serializable;
import java.lang.reflect.Method;
import java.util.Iterator;
import java.util.List;

import org.hibernate.Query;
import org.hibernate.SQLQuery;
import org.hibernate.Session;
import org.springframework.orm.hibernate3.HibernateTemplate;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;

@SuppressWarnings({ "rawtypes", "unchecked" })
public abstract class BaseDao<T extends BaseObj> extends HibernateDaoSupport implements GlobalParameters{
	protected Class	classT;

	public Class getClassT() {
		return classT;
	}

	public void setClassT(Class classT) {
		this.classT = classT;
	}

	public BaseDao(Class t) {
		this.classT = t;
	}
	
	public BaseDao() {
		setClassFromFather();
	}

	//通过子类构造器调用时确定classT的类型
	protected void setClassFromFather() {
		Class<?> c = TypeUtil.getClassType(this);
		setClassT(c);
	}
	
	public T get(Serializable id){
		return (T) this.getHibernateTemplate().get(classT, id);
	}
	
	public T load(Serializable id){
		return (T) this.getHibernateTemplate().load(classT, id);
	}
	
	public Long create(T entity){
		Session s = this.getSession();
		Long id = DataBaseUtil.generateId(s, entity.getTableName());
		entity.setId(id);
		s.save(entity);
		return id;
	}
	
	public void update(T entity){
		this.getHibernateTemplate().update(entity);
	}
	
	public void delete(T entity){
		SQLQuery qu = this.getSession().createSQLQuery("delete from " + entity.getTableName() + " where 1=1 and id=:id");
		qu.setLong("id", entity.getId()).executeUpdate();
	}
	
	public List<T> find(ConditionQuery q,boolean needInit){
		HibernateTemplate t = this.getHibernateTemplate();
		List<T> list = t.find(q.getHql(), q.getValueArray());
		if(needInit){
			initGetMethods(list,t);
		}
		return list;
	}
	
	public List<T> find(String orders,boolean needInit,AbsCondition... c){
		ConditionQuery q = new ConditionQuery(classT.getName(),orders,c);
		return this.find(q,needInit);
	}
	
	public List<T> find(String orders,boolean needInit){
		ConditionQuery q = new ConditionQuery(classT.getName(),orders);
		return this.find(q,needInit);
	}
	
	public void export(ConditionQuery q,DownLoader<T> downLoader){
		Query query = this.getSession().createQuery(q.getHql());
		for(int i=0;i<q.getValueArray().length;i++){
			Serializable s = q.getValueArray()[i];
			query.setParameter(i, s);
		}
		Iterator itr = query.iterate();
		while(itr.hasNext()){
			downLoader.handleRow((T)itr.next());
		}
	}
	
	private void initGetMethods(List<T> list,HibernateTemplate t) {
		if(list!=null && list.size()>0)
			for(T pojo:list){
				Method[] methods = pojo.getClass().getMethods();
				for (Method method : methods) {
					InitCollection annon = method.getAnnotation(InitCollection.class);
					if(method.getName().startsWith("set") 
							&& annon!=null
							&& annon.className()!=null ){
						String hql = " from " + annon.className().getName() + " t where 1=1 and t." + annon.forginKey() + "=? order by id desc";
						List subList = t.find(hql,pojo.getPk());
						try {
							method.invoke(pojo, subList);
						} catch (Exception e) {
							e.printStackTrace();
						}
					}
				}
			}
	}

}
